using System;
using MvpFramework.Infastructure;
using NUnit.Framework;
using Rhino.Mocks;

namespace MvpFramework.UnitTests
{
    [TestFixture]
    public class GenericTypeResolverTestFixture
    {
        private SomeSillyView _sillyView;
        private GenericTypeResolver _resolver;
        private Type _expectedType;
        private DeeplyNestedView _deeplyNestedView;
        private AViewWithNoPresenter _viewWithNoPresenter;
        private SomethingThatIsNotAMvpView _invalidView;

        private void Arrange()
        {
            var mocker = new MockRepository();
            _sillyView = mocker.DynamicMock<SomeSillyView>();
            _deeplyNestedView = mocker.DynamicMock<DeeplyNestedView>();
            _viewWithNoPresenter = mocker.DynamicMock<AViewWithNoPresenter>();
            _invalidView = mocker.DynamicMock<SomethingThatIsNotAMvpView>();
        }

        private void Act()
        {
            _resolver = new GenericTypeResolver();
        }

        [Test]
        public void GetPresenterTypeFor_returns_the_correct_presenter_for_a_nested_view()
        {
            Arrange();
            _expectedType = typeof (PresenterThatShouldBeUsedForDeeplyNestedView);
            Act();
            Assert.AreEqual(_expectedType, _resolver.GetPresenterTypeFor(_deeplyNestedView));
        }

        [Test]
        public void GetPresenterTypeFor_returns_the_correct_presenter_for_a_view()
        {
            Arrange();
            Act();
            _expectedType = typeof (MyPresenter);
            Assert.AreEqual(_expectedType, _resolver.GetPresenterTypeFor(_sillyView));
        }

        [Test]
        [ExpectedException(typeof (InvalidOperationException))]
        public void GetPresenterTypeFor_throws_InvalidOperationException_if_presenter_is_not_found()
        {
            Arrange();
            Act();
            _resolver.GetPresenterTypeFor(_viewWithNoPresenter);
        }

        [Test]
        public void GetViewTypeFor_returns_the_correct_presenter_for_a_nested_view()
        {
            Arrange();
            _expectedType = typeof (DeeplyNestedView);
            Act();
            Assert.AreEqual(_expectedType, _resolver.GetViewTypeFor(_deeplyNestedView));
        }

        [Test]
        public void GetViewTypeFor_returns_the_correct_view_for_a_page()
        {
            Arrange();
            _expectedType = typeof (SomeSillyView);
            Act();
            Assert.AreEqual(_expectedType, _resolver.GetViewTypeFor(_sillyView));
        }

        [Test]
        [ExpectedException(typeof (InvalidOperationException))]
        public void GetViewTypeFor_throws_InvalidOperationExpection_if_view_does_not_inherit_IMvpView()
        {
            Arrange();
            Act();
            _resolver.GetViewTypeFor(_invalidView);
        }
    }

    public interface SomethingThatIsNotAMvpView
    {
    }

    public interface AViewWithNoPresenter : IMvpView
    {
    }

    public interface SomeSillyView : IMvpView
    {
    }

    public class MyPresenter : Presenter<SomeSillyView>
    {
        public MyPresenter(SomeSillyView view)
            : base(view)
        {
        }
    }

    public interface DeeplyNestedView : SomeSillyView
    {
    }

    public class PresenterThatShouldBeUsedForDeeplyNestedView : Presenter<DeeplyNestedView>
    {
        public PresenterThatShouldBeUsedForDeeplyNestedView(DeeplyNestedView view)
            : base(view)
        {
        }
    }
}